﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Input;
using System.Diagnostics;

namespace Douban.Core.Helpers
{
    public class WindowDisplayHelper : DependencyObject
    {
        private Window _window;
        private bool _processing;
        private const double UpAnimationDuration = 300; 
        private const double DefaultHiddenBarThickness = 8.0;

        private WindowDisplayHelper() { }

        private WindowDisplayHelper(Window window)
        {
            _window = window;
            _window.Activated += Window_Activated;
            _window.MouseEnter += Window_MouseEnter;
            _window.MouseLeave += Window_MouseLeave;
            _window.StateChanged += Window_StateChanged;
        }

        
        public static readonly DependencyProperty WindowDisplayHelperProperty =
            DependencyProperty.Register("Instance", typeof(WindowDisplayHelper), 
            typeof(WindowDisplayHelper), new UIPropertyMetadata(null));

        public static WindowDisplayHelper GetInstance(Window window)
        {
            WindowDisplayHelper instance = (WindowDisplayHelper)window.GetValue(WindowDisplayHelperProperty);
            if (instance == null)
            {
                instance = new WindowDisplayHelper(window);
                window.SetValue(WindowDisplayHelperProperty, instance);
            }

            return instance;
        }

        public void Toggle(bool force = true)
        {
            if (_window.WindowState == WindowState.Minimized)
            {
                _window.WindowState = WindowState.Normal;
            }
            else
            {
                if (_window.Top > 0 && force)
                {
                    _window.WindowState = WindowState.Minimized;
                    return;
                }

                _processing = true;

                if (_window.Top < 0) ShowWindowAnimatedly();
                if (_window.Top == 0) HideWindowAnimatedly();

                _processing = false;
            }
        }

        private void Window_Activated(object sender, EventArgs e)
        {
            Debug.WriteLine("Toggle: Window_Activated");
            Window window = (Window)sender;
            window.Topmost = true;
            Toggle(false);
        }

        private void Window_StateChanged(object sender, EventArgs e)
        {
            Window window = (Window)sender;
            if (window.WindowState == WindowState.Normal)
            {
                Debug.WriteLine("Toggle: Window_StateChanged");
                window.Activate();
            }
        }

        private void Window_MouseEnter(object sender, MouseEventArgs e)
        {
            if (!_processing && _window.Top < 0)
            {
                ShowWindowAnimatedly();
            }
        }

        private void Window_MouseLeave(object sender, MouseEventArgs e)
        {
            if (_window.Top == 0)
            {
                if (InRange(e.GetPosition(_window))) return;

                _window.Topmost = true;

                HideWindowAnimatedly();
            }

            if (_window.Top > 0)
            {
                _window.Topmost = false;
            }
        }

        private void upAnimation_Completed(object sender, EventArgs e)
        {
            AnimationClock clock = (AnimationClock)sender;
            DoubleAnimation animation = (DoubleAnimation)clock.Timeline;
            _window.Top = (double)animation.To;
            _window.BeginAnimation(Window.TopProperty, null);
        }

        private bool InRange(System.Windows.Point point)
        {
            return (point.X > DefaultHiddenBarThickness
                        && point.X < _window.Width - DefaultHiddenBarThickness) &&
                   (point.Y > DefaultHiddenBarThickness
                        && point.Y <= _window.Height - DefaultHiddenBarThickness);
        }

        public void HideWindowAnimatedly()
        {
            DoubleAnimation upAnimation = new DoubleAnimation();
            upAnimation.To = DefaultHiddenBarThickness / 2 - _window.Height;
            upAnimation.Duration = TimeSpan.FromMilliseconds(UpAnimationDuration);
            upAnimation.Completed += upAnimation_Completed;
            _window.BeginAnimation(Window.TopProperty, upAnimation);
        }

        public void ShowWindowAnimatedly()
        {
            DoubleAnimation upAnimation = new DoubleAnimation();
            upAnimation.To = 0;
            upAnimation.Duration = TimeSpan.FromMilliseconds(UpAnimationDuration);
            upAnimation.Completed += upAnimation_Completed;
            _window.BeginAnimation(Window.TopProperty, upAnimation);
        }
    }
}
